package com.cooksys.film_rental.controllers;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;

import com.cooksys.film_rental.bo.ActorBo;
import com.cooksys.film_rental.bo.CategoryBo;
import com.cooksys.film_rental.bo.FilmBo;
import com.cooksys.film_rental.bo.LanguageBo;
import com.cooksys.film_rental.model.Actor;
import com.cooksys.film_rental.model.Category;
import com.cooksys.film_rental.model.Film;
import com.cooksys.film_rental.model.Language;
import com.cooksys.film_rental.model.forms.AdvancedFilmSearchForm;
import com.cooksys.film_rental.model.forms.CheckoutForm;
import com.cooksys.film_rental.model.forms.FilmSearchForm;

@Controller
@SessionAttributes({ "checkoutForm", "filmSearchForm",
		"advancedFilmSearchForm", "categoryMap", "actorMap", "languageMap",
		"ratingMap", "runtimeMap", "searchResults" })
public class FilmController {

	@Autowired
	FilmBo filmBo;

	@Autowired
	CategoryBo categoryBo;

	@Autowired
	ActorBo actorBo;

	@Autowired
	LanguageBo languageBo;

	@RequestMapping(value = "/films", method = RequestMethod.GET)
	public String films() {
		return "loggedoutFilmSearchView";
	}
	
	@RequestMapping(value = "/films/listings", method = RequestMethod.GET)
	public String filmListing(@RequestParam("id") Short filmId, ModelMap model) {
		
		Film film = filmBo.getFilmByFilmId(filmId);
		model.addAttribute("film", film);
		model.addAttribute("categoryList", categoryBo.searchCategoriesByFilm(film));
		model.addAttribute("actorList", actorBo.searchActorsByFilm(film));
		
		return "loggedoutFilmListingView";
	}

	@RequestMapping(value = "/films/search", method = RequestMethod.POST)
	public String search(
			@ModelAttribute("filmSearchForm") @Valid FilmSearchForm filmSearchForm,
			BindingResult result, ModelMap model) {

		if (result.hasErrors()) {
			return "loggedoutFilmSearchView";
		}

		List<Film> searchResults = filmBo
				.searchFilmsByPartialTitle(filmSearchForm.getSearchString());

		model.addAttribute("searchResults", searchResults);

		return "loggedoutSearchResultsView";

	}

	@RequestMapping(value = "/films/search/advanced", method = RequestMethod.POST)
	public String advancedSearch(
			@ModelAttribute("advancedFilmSearchForm") @Valid AdvancedFilmSearchForm advancedFilmSearchForm,
			BindingResult result, ModelMap model) {

		if (result.hasErrors()) {
			return "loggedoutFilmSearchView";
		}

		String partialTitle = advancedFilmSearchForm.getSearchString();
		Category categoryFilter = categoryBo
				.getCategoryByCategoryId(advancedFilmSearchForm.getCategoryId());
		Actor actorFilter = actorBo.getActorbyActorId(advancedFilmSearchForm
				.getActorId());
		Language languageFilter = languageBo
				.getLanguageByLanguageId(advancedFilmSearchForm.getLanguageId());
		Language orginalLanguageFilter = languageBo
				.getLanguageByLanguageId(advancedFilmSearchForm
						.getOriginalLanguageId());
		String ratingFilter = advancedFilmSearchForm.getRating();
		String runtimeFilter = advancedFilmSearchForm.getRuntime();

		List<Film> searchResults = filmBo.advancedSearch(partialTitle,
				categoryFilter, actorFilter, languageFilter,
				orginalLanguageFilter, ratingFilter, runtimeFilter);

		model.addAttribute("searchResults", searchResults);

		return "loggedoutSearchResultsView";

	}

	@ModelAttribute("searchResults")
	private List<Film> initSearchResults() {
		List<Film> searchResults = new ArrayList<Film>();
		return searchResults;
	}

	@ModelAttribute("filmSearchForm")
	private FilmSearchForm initFilmSearchForm() {
		FilmSearchForm filmSearchForm = new FilmSearchForm();
		return filmSearchForm;
	}

	@ModelAttribute("categoryMap")
	private Map<String, String> populateCategoryMap() {

		Map<String, String> categoryIdToDisplayValueMapping = new LinkedHashMap<String, String>();

		List<Category> categories = categoryBo.getAllCategories();

		categoryIdToDisplayValueMapping.put("0", "--- ALL ---");

		for (Category c : categories) {
			categoryIdToDisplayValueMapping.put(c.getCategoryId().toString(),
					c.getName());
		}

		return categoryIdToDisplayValueMapping;

	}

	@ModelAttribute("actorMap")
	private Map<String, String> populateActorMap() {

		Map<String, String> actorIdToDisplayValueMapping = new LinkedHashMap<String, String>();

		List<Actor> actors = actorBo.getAllActors();

		actorIdToDisplayValueMapping.put("0", "--- ALL ---");

		for (Actor a : actors) {
			actorIdToDisplayValueMapping.put(a.getActorId().toString(),
					a.getFirstName() + " " + a.getLastName());
		}

		return actorIdToDisplayValueMapping;

	}

	@ModelAttribute("languageMap")
	private Map<String, String> populateLanguageMap() {

		Map<String, String> languageIdToDisplayValueMapping = new LinkedHashMap<String, String>();

		List<Language> languages = languageBo.getAllLanguages();

		languageIdToDisplayValueMapping.put("0", "--- ALL ---");

		for (Language l : languages) {
			languageIdToDisplayValueMapping.put(l.getLanguageId().toString(),
					l.getName());
		}

		return languageIdToDisplayValueMapping;

	}

	@ModelAttribute("ratingMap")
	private Map<String, String> populateRatingMap() {

		Map<String, String> ratingKeyToDisplayValueMapping = new LinkedHashMap<String, String>();

		List<String> ratings = filmBo.getAllRatings();

		ratingKeyToDisplayValueMapping.put("ALL", "--- ALL ---");

		for (String r : ratings) {
			ratingKeyToDisplayValueMapping.put(r, r);
		}

		return ratingKeyToDisplayValueMapping;

	}

	@ModelAttribute("runtimeMap")
	private Map<String, String> populateRuntimeMap() {

		Map<String, String> runtimeKeyToDisplayValueMapping = new LinkedHashMap<String, String>();

		short maxRuntime = filmBo.getMaxRuntime();

		runtimeKeyToDisplayValueMapping.put("ALL", "--- ALL ---");

		for (short i = 0; i < maxRuntime + 10; i += 10) {

			runtimeKeyToDisplayValueMapping.put("" + i, "less than " + i
					+ " minutes");

		}

		return runtimeKeyToDisplayValueMapping;

	}

	@ModelAttribute("advancedFilmSearchForm")
	private AdvancedFilmSearchForm initAdvancedFilmSearchForm() {
		AdvancedFilmSearchForm advancedFilmSearchForm = new AdvancedFilmSearchForm();
		return advancedFilmSearchForm;

	}

	@ModelAttribute("checkoutForm")
	private CheckoutForm initCheckoutForm() {
		CheckoutForm checkoutForm = new CheckoutForm();
		return checkoutForm;
	}
}